using System;
using RockHopper.Common.Data;
using RockHopper.Common.Events;
using RockHopper.Common.Model;
using RockHopper.Common.Services;
using RockHopper.TrainingCalculator.WinRT.Common;
using RockHopper.TrainingCalculator.WinRT.Utils;
using Windows.ApplicationModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;

namespace RockHopper.TrainingCalculator.WinRT.Controls
{
    public class RacePerformanceControl : Control
    {
        private Slider hourSlider;
        private TextBlock hourTextblock;
        private Slider minuteSlider;
        private TextBlock minuteTextblock;
        private Slider secondSlider;
        private TextBlock secondTextblock;
        private TextBox distanceText;
        private RadioButton kilometreUnitsButton;
        private RadioButton metreUnitsButton;
        private RadioButton mileUnitsButton;
        private Button updateVdotButton;
        private UnitType units;
        private static readonly Style textBlockStyle =
            Common.Resources.TrainingStyles.Get<Style>("ValueTextBoxStyle");
        private static readonly Style textBlockErrorStyle =
            Common.Resources.TrainingStyles.Get<Style>("ValueTextBoxErrorStyle");
        private static readonly ISettingsRepository settingsRepository;
        private static readonly ICalculationService calculationService;
        private const string UpdateButtonTextTemplate = "Update VDOT ({0})";

        public RacePerformanceControl()
        {
            DefaultStyleKey = typeof(RacePerformanceControl);
            
        }

        static RacePerformanceControl()
        {
            if (!DesignMode.DesignModeEnabled)
            {
                settingsRepository = Global.Container.Resolve<ISettingsRepository>();
                calculationService = Global.Container.Resolve<ICalculationService>();
            }
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            hourSlider = (Slider)GetTemplateChild("HourSliderPart");
            hourTextblock = (TextBlock)GetTemplateChild("HourTextBlockPart");
            minuteSlider = (Slider)GetTemplateChild("MinuteSliderPart");
            minuteTextblock = (TextBlock)GetTemplateChild("MinuteTextBlockPart");
            secondSlider = (Slider)GetTemplateChild("SecondSliderPart");
            secondTextblock = (TextBlock)GetTemplateChild("SecondTextBlockPart");
            updateVdotButton = (Button) GetTemplateChild("UpdateButtonPart");
            distanceText = (TextBox)GetTemplateChild("DistancePart");

            updateVdotButton.Click += (s, e) => RaiseVdotChanged();
            hourSlider.ValueChanged += OnHourSliderValueChanged;
            minuteSlider.ValueChanged += OnMinuteSliderValueChanged;
            secondSlider.ValueChanged += OnSecondSliderValueChanged;

            kilometreUnitsButton = (RadioButton)GetTemplateChild("KilometresButtonPart");
            kilometreUnitsButton.Tag = UnitType.Kilometres;
            kilometreUnitsButton.Checked += OnUnitsChanged;
            kilometreUnitsButton.IsChecked = true;

            metreUnitsButton = (RadioButton)GetTemplateChild("MetresButtonPart");
            metreUnitsButton.Tag = UnitType.Metres;
            metreUnitsButton.Checked += OnUnitsChanged;

            mileUnitsButton = (RadioButton)GetTemplateChild("MilesButtonPart");
            mileUnitsButton.Tag = UnitType.Miles;
            mileUnitsButton.Checked += OnUnitsChanged;

            distanceText.TextChanged += OnDistanceTextChanged;

            UpdateRacePerformance(settingsRepository.Vdot, 10);

            DomainEvents.VdotChanged += OnVdotChanged;
        }

        private void OnUnitsChanged(object sender, RoutedEventArgs args)
        {
            var button = (RadioButton) sender;
            units = (UnitType)button.Tag;
        }

        private void OnVdotChanged(object sender, VdotChangedEventArgs args)
        {
            updateVdotButton.Content = string.Format(UpdateButtonTextTemplate, settingsRepository.Vdot.RoundToString());
        }

        private void OnDistanceTextChanged(object sender, TextChangedEventArgs e)
        {
            double distance;

            if (!double.TryParse(distanceText.Text, out distance) || distance < 0)
            {
                distanceText.Style = textBlockErrorStyle;
            }
            else
            {
                distanceText.Style = textBlockStyle;
            }
        }

        private void OnHourSliderValueChanged(object sender, RangeBaseValueChangedEventArgs args)
        {
            var hours = (int)args.NewValue;
            hourTextblock.Text = hours.ToString();
        }

        private void OnMinuteSliderValueChanged(object sender, RangeBaseValueChangedEventArgs args)
        {
            var minutes = (int)args.NewValue;
            minuteTextblock.Text = minutes.ToString();
        }

        private void OnSecondSliderValueChanged(object sender, RangeBaseValueChangedEventArgs args)
        {
            var seconds = (int)args.NewValue;
            secondTextblock.Text = seconds.ToString();
        }

        private void RaiseVdotChanged()
        {
            double distance;
            double vdot;

            if (!double.TryParse(distanceText.Text, out distance))
            {
                vdot = Vdot.Minimum;
            }
            else
            {
                var hours = (int)hourSlider.Value;
                var minutes = (int) minuteSlider.Value;
                var seconds = (int) secondSlider.Value;
                vdot = Vdot.Resolve(distance.ToMetres(units), hours, minutes, seconds);
                settingsRepository.Vdot = vdot;
                updateVdotButton.Content = string.Format(UpdateButtonTextTemplate, vdot.RoundToString());
            }

            DomainEvents.RaiseVdotChanged(this, new VdotChangedEventArgs(vdot));
        }

        private void UpdateRacePerformance(double fromVdot, double distance)
        {
            var raceTime = calculationService.RaceTime(fromVdot, distance.ToMetres(units));
            var time = TimeSpan.FromMinutes(raceTime);
            updateVdotButton.Content = string.Format(UpdateButtonTextTemplate, fromVdot.RoundToString());
            hourSlider.Value = time.Hours;
            minuteSlider.Value = time.Minutes;
            secondSlider.Value = time.Seconds;
        }
    }
}